/**
 *******************************************************************************
 * @file  eth/eth_loopback/source/ethernetif.c
 * @brief This file implements Ethernet network interface drivers.
 @verbatim
   Change Logs:
   Date             Author          Notes
   2022-03-31       CDT             First version
   2023-01-15       CDT             Delect RX_ER Pin in RMII mode
   2023-09-30       CDT             Modify the process of obtaining PHY status
                                    Add MAC interface selection before ETH_DeInit function
                                    Disable auto negotiation in low_level_init function
   2024-11-08       CDT             Strip PHY operation code into BSP file
                                    Add high driver for ETH output pin
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2022-2025, Xiaohua Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by XHSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
 
#include <string.h>
#include <stdlib.h>
#include "ethernetif.h"

#include "netif/etharp.h"
 
#include "hc32_ll.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#include "bsp_common.h"
#include "bsp_rtl8201.h"

/**
 * @addtogroup HC32F4A0_DDL_Examples
 * @{
 */

/**
 * @addtogroup ETH_Loopback
 * @{
 */

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
/* Define those to better describe your network interface. */
#define IFNAME0                         'h'
#define IFNAME1                         'd'

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/
/* Global Ethernet handle*/

#define LOWLEVEL_OUTPUT_WAITING_TIME (250)
#define LOWLEVEL_INPUT_WAITING_TIME  ((portTickType)100)

#define ETH_DMA_INT_SRC           (INT_SRC_ETH_GLB_INT)
#define ETH_DMA_GLB_INT_IRQn      (INT001_IRQn)
#define ETH_DMA_INT_PRIO          (DDL_IRQ_PRIO_02)

static stc_eth_handle_t EthHandle;
/* Ethernet Tx DMA Descriptor */
__ALIGN_BEGIN static stc_eth_dma_desc_t EthDmaTxDscrTab[ETH_TX_BUF_NUM];
/* Ethernet Rx DMA Descriptor */
__ALIGN_BEGIN static stc_eth_dma_desc_t EthDmaRxDscrTab[ETH_RX_BUF_NUM];
/* Ethernet Transmit Buffer */
__ALIGN_BEGIN static uint8_t EthTxBuff[ETH_TX_BUF_NUM][ETH_TX_BUF_SIZE];
/* Ethernet Receive Buffer */
__ALIGN_BEGIN static uint8_t EthRxBuff[ETH_RX_BUF_NUM][ETH_RX_BUF_SIZE];

static xSemaphoreHandle g_rx_semaphore = NULL;
uint8_t MACAddr[6];
int errno;

void ETH_IRQHandler(void);

void Ethernet_GetMacAddr(uint8_t *p)
{
    uint8_t i;
    uint8_t *macaddr = (uint8_t *)(ROM_CFG_USERADR_ID + 5);

    for (i = 0; i < 6; i++) {
        *p = *macaddr;
        p++;
        macaddr--;
    }
}

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @defgroup ETH_IF_Global_Functions Ethernet Interface Global Functions
 * @{
 */

/**
 * @brief  Initializes the Ethernet GPIO.
 * @param  None
 * @retval None
 */
static void Ethernet_GpioInit(void)
{
    stc_gpio_init_t stcGpioInit;

    (void)GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinDrv = PIN_HIGH_DRV;
    /* Configure MII/RMII selection IO for ETH */
#ifdef ETH_INTERFACE_RMII
    /* Ethernet RMII pins configuration */
    /**
        ETH_RMII_TX_EN --------------> PB11
        ETH_RMII_TXD0 ---------------> PB12
        ETH_RMII_TXD1 ---------------> PB13
        ETH_RMII_REF_CLK ------------> PA1
        ETH_RMII_CRS_DV -------------> PA7
        ETH_RMII_RXD0 ---------------> PC4
        ETH_RMII_RXD1 ---------------> PC5
    */
    GPIO_Init(GPIO_PORT_B, (GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13), &stcGpioInit);
    /* Configure PA1 and PA7 */
    GPIO_SetFunc(GPIO_PORT_A, (GPIO_PIN_01 | GPIO_PIN_07), GPIO_FUNC_11);
    /* Configure PC4 and PC5 */
    GPIO_SetFunc(GPIO_PORT_C, (GPIO_PIN_04 | GPIO_PIN_05), GPIO_FUNC_11);
    /* Configure PG11, PG13 and PG14 */
    GPIO_SetFunc(GPIO_PORT_B, (GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13), GPIO_FUNC_11);
#else
    /* Ethernet MII pins configuration */
    /**
        ETH_MII_TX_CLK --------------> PB6
        ETH_MII_TX_EN ---------------> PG11
        ETH_MII_TXD0 ----------------> PG13
        ETH_MII_TXD1 ----------------> PG14
        ETH_MII_TXD2 ----------------> PB9
        ETH_MII_TXD3 ----------------> PB8
        ETH_MII_RX_CLK --------------> PA1
        ETH_MII_RX_DV ---------------> PA7
        ETH_MII_RXD0 ----------------> PC4
        ETH_MII_RXD1 ----------------> PC5
        ETH_MII_RXD2 ----------------> PB0
        ETH_MII_RXD3 ----------------> PB1
        ETH_MII_RX_ER ---------------> PI10
        ETH_MII_CRS -----------------> PH2
        ETH_MII_COL -----------------> PH3
    */
    GPIO_Init(GPIO_PORT_B, (GPIO_PIN_08 | GPIO_PIN_09), &stcGpioInit);
    GPIO_Init(GPIO_PORT_G, (GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14), &stcGpioInit);
    /* Configure PA1 and PA7 */
    GPIO_SetFunc(GPIO_PORT_A, (GPIO_PIN_01 | GPIO_PIN_07), GPIO_FUNC_11);
    /* Configure PB0, PB1, PB6, PB8 and PB9 */
    GPIO_SetFunc(GPIO_PORT_B, (GPIO_PIN_00 | GPIO_PIN_01 | GPIO_PIN_06 | GPIO_PIN_08 | GPIO_PIN_09), GPIO_FUNC_11);
    /* Configure PC4 and PC5 */
    GPIO_SetFunc(GPIO_PORT_C, (GPIO_PIN_04 | GPIO_PIN_05), GPIO_FUNC_11);
    /* Configure PG11, PG13 and PG14 */
    GPIO_SetFunc(GPIO_PORT_G, (GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14), GPIO_FUNC_11);
    /* Configure PH2, PH3 */
    GPIO_SetFunc(GPIO_PORT_H, (GPIO_PIN_02 | GPIO_PIN_03), GPIO_FUNC_11);
    /* Configure PI10 */
    GPIO_SetFunc(GPIO_PORT_I, GPIO_PIN_10, GPIO_FUNC_11);
#endif
}

/**
 * @brief  In this function, the hardware should be initialized.
 * @param  netif                         The already initialized network interface structure for this ethernetif.
 * @retval int32_t:
 *           - LL_OK: Initialize success
 *           - LL_ERR: Initialize failed
 */
static void
low_level_init(struct netif *netif)
{
    int32_t i32Ret = LL_OK;
    stc_eth_init_t stcEthInit;

    /* Enable ETH clock */
    FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_ETHMAC, ENABLE);
    /* Init Ethernet GPIO */
    Ethernet_GpioInit();
    /* PHY initialization */
    BSP_RTL8201_Init();
    
    /* Configure structure initialization */
    (void)ETH_CommStructInit(&EthHandle.stcCommInit);
    (void)ETH_StructInit(&stcEthInit);
#ifdef ETH_INTERFACE_RMII
    EthHandle.stcCommInit.u32Interface  = ETH_MAC_IF_RMII;
#else
    EthHandle.stcCommInit.u32Interface  = ETH_MAC_IF_MII;
#endif
    stcEthInit.stcMacInit.u32ReceiveAll = ETH_MAC_RX_ALL_ENABLE;
#ifdef CHECKSUM_BY_HARDWARE
    EthHandle.stcCommInit.u32ChecksumMode = ETH_MAC_CHECKSUM_MD_HW;
#else
    EthHandle.stcCommInit.u32ChecksumMode = ETH_MAC_CHECKSUM_MD_SW;
#endif
    EthHandle.stcCommInit.u32ReceiveMode = ETH_RX_MD_INT;

    Ethernet_GetMacAddr(&MACAddr[0]);
    (EthHandle.stcCommInit).au8MacAddr[0] = MACAddr[0];
    (EthHandle.stcCommInit).au8MacAddr[1] = MACAddr[1];
    (EthHandle.stcCommInit).au8MacAddr[2] = MACAddr[2];
    (EthHandle.stcCommInit).au8MacAddr[3] = MACAddr[3];
    (EthHandle.stcCommInit).au8MacAddr[4] = MACAddr[4];
    (EthHandle.stcCommInit).au8MacAddr[5] = MACAddr[5];

    /* Configure ethernet peripheral */
    ETH_Init(&EthHandle, &stcEthInit);
    /* Initialize Tx Descriptors list: Chain Mode */
    (void)ETH_DMA_TxDescListInit(&EthHandle, EthDmaTxDscrTab, &EthTxBuff[0][0], ETH_TX_BUF_NUM);
    /* Initialize Rx Descriptors list: Chain Mode  */
    (void)ETH_DMA_RxDescListInit(&EthHandle, EthDmaRxDscrTab, &EthRxBuff[0][0], ETH_RX_BUF_NUM);

    /* set MAC hardware address length */
    netif->hwaddr_len = 6U;
    /* set MAC hardware address */
    netif->hwaddr[0] = (EthHandle.stcCommInit).au8MacAddr[0];
    netif->hwaddr[1] = (EthHandle.stcCommInit).au8MacAddr[1];
    netif->hwaddr[2] = (EthHandle.stcCommInit).au8MacAddr[2];
    netif->hwaddr[3] = (EthHandle.stcCommInit).au8MacAddr[3];
    netif->hwaddr[4] = (EthHandle.stcCommInit).au8MacAddr[4];
    netif->hwaddr[5] = (EthHandle.stcCommInit).au8MacAddr[5];
    /* maximum transfer unit */
    netif->mtu = 1500U;
    
    /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;

    /* create binary semaphore used for informing ethernetif of frame reception */
    if (g_rx_semaphore == NULL) {
        vSemaphoreCreateBinary(g_rx_semaphore);
        xSemaphoreTake(g_rx_semaphore, 0);
    }

    stc_irq_signin_config_t stcIrqSignConfig;
    /* IRQ sign-in */
    stcIrqSignConfig.enIntSrc = ETH_DMA_INT_SRC;
    stcIrqSignConfig.enIRQn   = ETH_DMA_GLB_INT_IRQn;
    stcIrqSignConfig.pfnCallback = &ETH_IRQHandler;
    (void)INTC_IrqSignIn(&stcIrqSignConfig);
    /* NVIC config */
    NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
    NVIC_SetPriority(stcIrqSignConfig.enIRQn, ETH_DMA_INT_PRIO);
    NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);

    /* Configure PHY */
    BSP_RTL8201_AutoNegoCmd(ENABLE);
    BSP_RTL8201_SetLinkMode(RTL8201_LINK_100M_FULL_DUPLEX);
#ifdef ETH_INTERFACE_RMII
    /* Disable Power Saving Mode */
    BSP_RTL8201_PowerSaveModeCmd(DISABLE);
#endif

    xTaskCreate(ethernetif_input, "ethernetif_input", 350, netif, configMAX_PRIORITIES - 1, NULL);
}

/**
 * @brief  This function should do the actual transmission of the packet.
 * @param  netif                        The network interface structure for this ethernetif.
 * @param  p                            The MAC packet to send.
 * @retval int32_t:
 *           - LL_OK: The packet could be sent
 *           - LL_ERR: The packet couldn't be sent
 */
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
    err_t i32Ret;
    struct pbuf *q;
    uint8_t *txBuffer;
    __IO stc_eth_dma_desc_t *DmaTxDesc;
    uint32_t byteCnt;
    uint32_t frameLength = 0UL;
    uint32_t bufferOffset;
    uint32_t payloadOffset;

    DmaTxDesc = EthHandle.stcTxDesc;
    txBuffer = (uint8_t *)((EthHandle.stcTxDesc)->u32Buf1Addr);
    bufferOffset = 0UL;
    /* Copy frame from pbufs to driver buffers */
    for (q = p; q != NULL; q = q->next) {
        /* If this buffer isn't available, goto error */
        if (0UL != (DmaTxDesc->u32ControlStatus & ETH_DMA_TXDESC_OWN)) {
            i32Ret = ERR_USE;
            goto error;
        }

        /* Get bytes in current buffer */
        byteCnt = q->len;
        payloadOffset = 0UL;
        /* Check if the length of data to copy is bigger than Tx buffer size */
        while ((byteCnt + bufferOffset) > ETH_TX_BUF_SIZE) {
            /* Copy data to Tx buffer*/
            (void)memcpy((uint8_t *) & (txBuffer[bufferOffset]), (uint8_t *) & (((uint8_t *)q->payload)[payloadOffset]), (ETH_TX_BUF_SIZE - bufferOffset));
            /* Point to next descriptor */
            DmaTxDesc = (stc_eth_dma_desc_t *)(DmaTxDesc->u32Buf2NextDescAddr);
            /* Check if the buffer is available */
            if (0UL != (DmaTxDesc->u32ControlStatus & ETH_DMA_TXDESC_OWN)) {
                i32Ret = ERR_USE;
                goto error;
            }

            txBuffer = (uint8_t *)(DmaTxDesc->u32Buf1Addr);
            byteCnt = byteCnt - (ETH_TX_BUF_SIZE - bufferOffset);
            payloadOffset = payloadOffset + (ETH_TX_BUF_SIZE - bufferOffset);
            frameLength = frameLength + (ETH_TX_BUF_SIZE - bufferOffset);
            bufferOffset = 0UL;
        }
        /* Copy the remaining bytes */
        (void)memcpy((uint8_t *) & (txBuffer[bufferOffset]), (uint8_t *) & (((uint8_t *)q->payload)[payloadOffset]), byteCnt);
        bufferOffset = bufferOffset + byteCnt;
        frameLength = frameLength + byteCnt;
    }
    /* Prepare transmit descriptors to give to DMA */
    (void)ETH_DMA_SetTransFrame(&EthHandle, frameLength);
    i32Ret = ERR_OK;

error:
    /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
    if (RESET != ETH_DMA_GetStatus(ETH_DMA_FLAG_UNS)) {
        /* Clear DMA UNS flag */
        ETH_DMA_ClearStatus(ETH_DMA_FLAG_UNS);
        /* Resume DMA transmission */
        WRITE_REG32(CM_ETH->DMA_TXPOLLR, 0UL);
    }

    return i32Ret;
}

/**
 * @brief  Should allocate a pbuf and transfer the bytes of the incoming packet from the interface into the pbuf.
 * @param  netif                        The network interface structure for this ethernetif.
 * @retval A pbuf filled with the received packet (including MAC header) or NULL on memory error.
 */
static struct pbuf *low_level_input(struct netif *netif)
{
    struct pbuf *p = NULL;
    struct pbuf *q;
    uint32_t len;
    uint8_t *rxBuffer;
    __IO stc_eth_dma_desc_t *DmaRxDesc;
    uint32_t byteCnt;
    uint32_t bufferOffset;
    uint32_t payloadOffset;
    uint32_t i;

    /* Get received frame */
    if (LL_OK != ETH_DMA_GetReceiveFrame(&EthHandle)) {
        return NULL;
    }

    /* Obtain the size of the packet */
    len = (EthHandle.stcRxFrame).u32Len;
    rxBuffer = (uint8_t *)(EthHandle.stcRxFrame).u32Buf;
    if (len > 0UL) {
        /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
        p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    }
    if (p != NULL) {
        DmaRxDesc = (EthHandle.stcRxFrame).pstcFSDesc;
        bufferOffset = 0UL;
        for (q = p; q != NULL; q = q->next) {
            byteCnt = q->len;
            payloadOffset = 0UL;

            /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size */
            while ((byteCnt + bufferOffset) > ETH_RX_BUF_SIZE) {
                /* Copy data to pbuf */
                (void)memcpy((uint8_t *) & (((uint8_t *)q->payload)[payloadOffset]), (uint8_t *) & (rxBuffer[bufferOffset]), (ETH_RX_BUF_SIZE - bufferOffset));
                /* Point to next descriptor */
                DmaRxDesc = (stc_eth_dma_desc_t *)(DmaRxDesc->u32Buf2NextDescAddr);
                rxBuffer = (uint8_t *)(DmaRxDesc->u32Buf1Addr);
                byteCnt = byteCnt - (ETH_RX_BUF_SIZE - bufferOffset);
                payloadOffset = payloadOffset + (ETH_RX_BUF_SIZE - bufferOffset);
                bufferOffset = 0UL;
            }

            /* Copy remaining data in pbuf */
            (void)memcpy((uint8_t *) & (((uint8_t *)q->payload)[payloadOffset]), (uint8_t *) & (rxBuffer[bufferOffset]), byteCnt);
            bufferOffset = bufferOffset + byteCnt;
        }
    }
    /* Release descriptors to DMA */
    DmaRxDesc = (EthHandle.stcRxFrame).pstcFSDesc;
    for (i = 0UL; i < (EthHandle.stcRxFrame).u32SegCount; i++) {
        DmaRxDesc->u32ControlStatus |= ETH_DMA_RXDESC_OWN;
        DmaRxDesc = (stc_eth_dma_desc_t *)(DmaRxDesc->u32Buf2NextDescAddr);
    }
    /* Clear Segment_Count */
    (EthHandle.stcRxFrame).u32SegCount = 0UL;

    /* When Rx Buffer unavailable flag is set, clear it and resume reception */
    if (RESET != ETH_DMA_GetStatus(ETH_DMA_FLAG_RUS)) {
        /* Clear DMA RUS flag */
        ETH_DMA_ClearStatus(ETH_DMA_FLAG_RUS);
        /* Resume DMA reception */
        WRITE_REG32(CM_ETH->DMA_RXPOLLR, 0UL);
    }

    return p;
}

/**
 * @brief  Should be called at the beginning of the program to set up the network interface.
 * @param  netif                        The network interface structure for this ethernetif.
 * @retval int32_t:
 *           - LL_OK: The IF is initialized
 *           - LL_ERR: The IF is uninitialized
 */
err_t ethernetif_init(struct netif *netif)
{
#if LWIP_NETIF_HOSTNAME
    /* Initialize interface hostname */
    netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
    netif->name[0] = IFNAME0;
    netif->name[1] = IFNAME1;
    /* We directly use etharp_output() here to save a function call.
    * You can instead declare your own function an call etharp_output()
    * from it if you have to do some checks before sending (e.g. if link
    * is available...) */
    netif->output = &etharp_output;
    netif->linkoutput = &low_level_output;
    /* initialize the hardware */
    low_level_init(netif);
    return (err_t)ERR_OK;
}

/**
 * @brief  This function should be called when a packet is ready to be read from the interface.
 * @param  netif                        The network interface structure for this ethernetif.
 * @retval None
 */
void ethernetif_input(void *pvParameters)
{
    struct pbuf *p;
    // SYS_ARCH_DECL_PROTECT(sr);

    struct netif *low_netif = (struct netif *)pvParameters;

    for (;;) {
        if (pdTRUE == xSemaphoreTake(g_rx_semaphore, LOWLEVEL_INPUT_WAITING_TIME)) {
        TRY_GET_NEXT_FRAME:
            // SYS_ARCH_PROTECT(sr);
            p = low_level_input(low_netif);
            // SYS_ARCH_UNPROTECT(sr);

            if (p != NULL) {
                if (ERR_OK != low_netif->input(p, low_netif)) {
                    pbuf_free(p);
                    p = NULL;
                } else {
                    goto TRY_GET_NEXT_FRAME;
                }
            }
        }
    }
}

/**
 * @brief  Check the netif link status.
 * @param  netif the network interface
 * @retval None
 */
void EthernetIF_CheckLink(void *pvParameters)
{
    uint16_t u16LinkStatus;
    struct netif *netif = (struct netif *)pvParameters;

    while(1)
    {
        if (LL_OK == BSP_RTL8201_GetLinkStatus(&u16LinkStatus)) {
            /* Check whether the link is up or down*/
            if ((!netif_is_link_up(netif)) && (u16LinkStatus > RTL8201_LINK_AUTO_NEGO_NOT_CPLT)) {
                netif_set_link_up(netif);
                EthernetIF_LinkCallback(netif);
                DDL_Printf("Link Up\r\n");
                BSP_LED4_ON();
            } else if (netif_is_link_up(netif) && (u16LinkStatus <= RTL8201_LINK_AUTO_NEGO_NOT_CPLT)) {
                netif_set_link_down(netif);
                EthernetIF_LinkCallback(netif);
                DDL_Printf("Link down\r\n");
                BSP_LED4_OFF();
            }
        }
        vTaskDelay(pdMS_TO_TICKS(LINK_TIMER_INTERVAL));
    }
    
    vTaskDelete(NULL);
}

/**
 * @brief  Link callback function
 * @note   This function is called on change of link status to update low level driver configuration.
 * @param  netif                        The network interface
 * @retval None
 */
void EthernetIF_LinkCallback(struct netif *netif)
{
    uint16_t u16LinkStatus;
    uint32_t u32DuplexMode = ETH_MAC_DUPLEX_MD_FULL;
    uint32_t u32Speed = ETH_MAC_SPEED_100M;

    if (netif_is_link_up(netif)) {
        if (LL_OK == BSP_RTL8201_GetLinkStatus(&u16LinkStatus)) {
            /* Check whether the link is up or down*/
            if (u16LinkStatus > RTL8201_LINK_AUTO_NEGO_NOT_CPLT) {
                switch (u16LinkStatus) {
                    case RTL8201_LINK_100M_FULL_DUPLEX:
                        u32DuplexMode   = ETH_MAC_DUPLEX_MD_FULL;
                        u32Speed        = ETH_MAC_SPEED_100M;
                        break;
                    case RTL8201_LINK_100M_HALF_DUPLEX:
                        u32DuplexMode   = ETH_MAC_DUPLEX_MD_HALF;
                        u32Speed        = ETH_MAC_SPEED_100M;
                        break;
                    case RTL8201_LINK_10M_FULL_DUPLEX:
                        u32DuplexMode   = ETH_MAC_DUPLEX_MD_FULL;
                        u32Speed        = ETH_MAC_SPEED_10M;
                        break;
                    case RTL8201_LINK_10M_HALF_DUPLEX:
                        u32DuplexMode   = ETH_MAC_DUPLEX_MD_HALF;
                        u32Speed        = ETH_MAC_SPEED_10M;
                        break;
                }
                /* ETH MAC Re-Configuration */
                ETH_MAC_SetDuplexSpeed(u32DuplexMode, u32Speed);
                /* Restart MAC interface */
                (void)ETH_Start();
            }
        }
    } else {
        /* Stop MAC interface */
        (void)ETH_Stop();
    }
}

void ETH_IRQHandler(void)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    if (RESET != ETH_DMA_GetStatus(ETH_DMA_FLAG_RIS)) {
        xSemaphoreGiveFromISR(g_rx_semaphore, &xHigherPriorityTaskWoken);
        ETH_DMA_ClearStatus(ETH_DMA_FLAG_RIS);
    }
//    if (RESET != ETH_DMA_GetStatus(ETH_DMA_FLAG_TIS)) {
//        ETH_DMA_ClearStatus(ETH_DMA_FLAG_TIS);
//    }
    ETH_DMA_ClearStatus(ETH_DMA_FLAG_NIS);

    /* switch tasks if necessary */
    if (pdFALSE != xHigherPriorityTaskWoken) {
        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
    }
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */

/******************************************************************************
 * EOF (not truncated)
 *****************************************************************************/
